package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author atguigu-mqx
 * @ClassName TestServiceImpl
 * @description: TODO
 * @date 2023年12月05日
 * @version: 1.0
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;
    /*
        1.  从缓存中获取一个num key的数据！
                set num 0
        2.  判断这个key对应的value是否为空
                true:
                    return
                false:
                    value+1;放入这个num中!
     */

    @Override
    public void testLock() {

        //  获取到锁对象
        RLock lock = redissonClient.getLock("lock");
        //  调用上锁方法.
        lock.lock();
        //  10秒之后锁自动释放
        lock.lock(10,TimeUnit.SECONDS);
        //  最大等待1秒{如果超过了这个时间，会自动放弃执行任务} 10秒之后锁自动释放
        boolean res = false;
        try {
            res = lock.tryLock(1, 10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        if (res){
            //  res = true 表示获取锁成功
            try {
                //  业务逻辑
                //  set num 0 ;
                String num = redisTemplate.opsForValue().get("num");
                //  判断
                if (StringUtils.isEmpty(num)) {
                    return;
                }
//            int i = 1/0; 出现宕机了.
                int numValue = Integer.parseInt(num);
                //  将数据存储到缓存 int i = 1/0;
                this.redisTemplate.opsForValue().set("num", String.valueOf(numValue + 1));
            } catch (NumberFormatException e) {
                throw new RuntimeException(e);
            } finally {
                //  解锁：
                lock.unlock();
            }
        }else {
            System.out.println("获取锁失败");
            //  testLock();
        }



    }
//    @Override
//    public void testLock() {
//        //  redis setnx key value;
//        //  redis setnx key value + setex key value;
//        String token = UUID.randomUUID().toString().replaceAll("-", "");
//        Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", token, 3, TimeUnit.SECONDS);
//        //  执行成功
//        if (result) {
//            try {
//                //  set num 0 ;
//                String num = redisTemplate.opsForValue().get("num");
//                //  判断
//                if (StringUtils.isEmpty(num)) {
//                    return;
//                }
//                int numValue = Integer.parseInt(num);
//                //  将数据存储到缓存 int i = 1/0;
//                this.redisTemplate.opsForValue().set("num", String.valueOf(numValue + 1));
//            } catch (NumberFormatException e) {
//                throw new RuntimeException(e);
//            } finally {
//                //  释放锁： del key 出现异常是否资源.
//                //  redis宕机了，这个锁也不会被删除！解决方案给key添加一个过期时间！
//                //                if (token.equals(redisTemplate.opsForValue().get("lock"))){
//                //                    //  index1
//                //                    this.redisTemplate.delete("lock");
////                                }
//                //  定义一个lua脚本
//                String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
//                        "then\n" +
//                        "    return redis.call(\"del\",KEYS[1])\n" +
//                        "else\n" +
//                        "    return 0\n" +
//                        "end";
//
//                //  创建RedisScript 对象
//                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
//                redisScript.setScriptText(scriptText);
//                redisScript.setResultType(Long.class);
//                //  第二个参数是锁的key 第三个参数：token
//                this.redisTemplate.execute(redisScript, Arrays.asList("lock"), token);
//            }
//        } else {
//            try {
//                //    自旋：
//                Thread.sleep(100);
//                testLock();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//    }
}
